package com.han.hotelplat.comm.base;

import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.NullableType;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.CollectionUtils;

/**
 * 
	 ***************************************************************
	 * <p>
	 * @CLASS				:	BaseDAO
	 * @DESCRIPTION	:	hibernate持久化管理
	 * @AUTHOR				:	han1088
	 * @VERSION			:	v1.0
	 * @DATE					:	2017年7月11日 上午10:01:33            
	 * </p>
	 * 
	 * <p>
	 * @MODIFY	LOG	:		
	 * @AUTHOR				:	han1088
	 * @VERSION			:	v1.0
	 * @MODIFY DATE	:	
	 * </p>    
	 ****************************************************************
 */

public class BaseDAO<T> extends HibernateDaoSupport implements IBaseDAO<T> {
	@Resource(name = "sessionFactory")
	public void setDaoSessionFactory(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
	}
	private String className;
	private String SQL = "";

	@SuppressWarnings("unchecked")
	public BaseDAO() {
		Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		className = entityClass.getName();
	}

	@Override
	public void save(T obj) {
		try{
			super.getHibernateTemplate().save(obj);
		}catch (DataAccessException e){
			e.printStackTrace();
		}
	}

	@Override
	public void saveAll(List<T> list) {
		for (T obj : list) {
			super.getHibernateTemplate().save(obj);
		}
	}

	@Override
	public void updateAll(List<T> list) {
		for (T obj : list) {
			super.getHibernateTemplate().update(obj);
		}
	}

	@Override
	public int updateByHQL(String HQL) {
		return super.getHibernateTemplate().bulkUpdate(HQL);
	}

	@Override
	public int updateByHQL(String HQL, Object obj) {
		return super.getHibernateTemplate().bulkUpdate(HQL, obj);
	}

	@Override
	public int updateByHQL(String HQL, Object[] objs) {
		if (objs == null || objs.length == 0){
			return super.getHibernateTemplate().bulkUpdate(HQL);
		}else{
			return super.getHibernateTemplate().bulkUpdate(HQL, objs);
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public int updateBySQL(final String SQL) {
		return (Integer) super.getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(SQL);
						return query.executeUpdate();
					}
				});
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public int updateBySQL(final String SQL, final Object obj) {
		return (Integer) super.getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(SQL);
						query.setParameter(0, obj);
						return query.executeUpdate();
					}
				});
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public int updateBySQL(final String SQL, final Object[] objs,final NullableType[] types) {
		return (Integer) super.getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(SQL);
						if (objs != null && objs.length > 0) {
							query.setParameters(objs, types);
						}
						return query.executeUpdate();
					}
				});
	}

	@Override
	public int deleteByProperty(String keyName, Object keyValue) {
		SQL = "delete " + className + " where " + keyName + "=?";
		return super.getHibernateTemplate().bulkUpdate(SQL, keyValue);
	}

	@Override
	public T deleteById(Object keyValue) {
		T instance = this.findById(keyValue);
		this.delete(instance);
		return instance;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public Integer deleteByIds(final Integer[] ids) {
		return (Integer) this.getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)throws HibernateException, SQLException {
						String HQL = "delete " + className + " where id in(:ids)";
						Query query = session.createQuery(HQL);
						query.setParameterList("ids", ids);
						return query.executeUpdate();
					}
				});
	}

	@Override
	public void delete(T obj) {
		super.getHibernateTemplate().delete(obj);
	}

	@Override
	@SuppressWarnings("unchecked")
	public T findById(Object key) {
		T instance = null;
		if (key instanceof String) {
			instance = (T) super.getHibernateTemplate().get(className,(String) key);
		} else if (key instanceof Integer) {
			instance = (T) super.getHibernateTemplate().get(className,(Integer) key);
		} else if (key instanceof Long) {
			instance = (T) super.getHibernateTemplate().get(className,(Long) key);
		}
		return instance;
	}

	@SuppressWarnings({ "unchecked" })
	@Override
	public List<T> findByProperty(String propertyName, Object value) {
		SQL = "from " + className + " where " + propertyName + " = ?";
		return super.getHibernateTemplate().find(SQL, value);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public List findByHQL(String HQL) {
		try {
			return super.getHibernateTemplate().find(HQL);
		} catch (RuntimeException re) {
			re.printStackTrace();
			throw re;
		}
	}

	@Override
	@SuppressWarnings("rawtypes")
	public List findByHQL(String HQL, Object args) {
		try {
			return super.getHibernateTemplate().find(HQL, args);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	@Override
	@SuppressWarnings("rawtypes")
	public List findByHQL(String HQL, Object[] args) {
		try {
			if (args == null || args.length == 0){
				return super.getHibernateTemplate().find(HQL);
			}else{
				return super.getHibernateTemplate().find(HQL, args);
			}
		} catch (RuntimeException re) {
			throw re;
		}
	}

	@SuppressWarnings({ "rawtypes", "deprecation" })
	public List findHql(final String HQL, final List<Object> paras) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				Query query = session.createQuery(HQL);
				if (paras != null && paras.size() > 0) {
					int parasCount = paras.size();
					for (int i = 0; i < parasCount; i++) {
						query.setParameter(i, paras.get(i));
					}
				}
				return query.list();
			}
		});
	}

	
	@Override
	@SuppressWarnings({ "rawtypes", "deprecation" })
	public List findPage(final String HQL, final List<Object> paras,
			final int first, final int size) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				Query query = session.createQuery(HQL);
				if (paras != null && paras.size() > 0) {
					int parasCount = paras.size();
					for (int i = 0; i < parasCount; i++) {
						query.setParameter(i, paras.get(i));
					}
				}
				query.setFirstResult(first);
				query.setMaxResults(size);
				return query.list();
			}
		});
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public int findCount(final String HQL, final List<Object> paras) {
		return (Integer) getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)throws HibernateException, SQLException {
						Query query = session.createQuery(HQL);
						if (paras != null && paras.size() > 0) {
							int parasCount = paras.size();
							for (int i = 0; i < parasCount; i++) {
								query.setParameter(i, paras.get(i));
							}
						}
						Long count = (Long) query.uniqueResult();
						return count.intValue();
					}
				});
	}

	/**
	 * 
	 * Function name:findBySql
	 * Description: 通过sql查找数据
	 * @param sql：sql字串
	 * @return:数据列表
	 */
	@SuppressWarnings({ "deprecation", "unchecked" })
	@Override
	public List<T> findBySql(String sql){
		Session session = this.getSession();
		try {
			List<T> rs = session.createSQLQuery(sql).addEntity(Class.forName(className)).list();
			return rs;
		} catch (Exception e) {
			e.printStackTrace();
			return new ArrayList<T>();
		}finally{
			this.releaseSession(session);
		}
	}
	
	@SuppressWarnings("deprecation")
	@Override
	public void sessionFlush() {
		this.getSession(false).flush();
	}

	/**
	 * 
	 * Function name:findAll
	 * Description: 查找指定表的所有数据
	 * @param tablename：所要查找的表的名字，表名在tbEntityDAO中有定义
	 * @return：表中所有数据的集合
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public List findAll(String tablename) {
		try {
			String queryString = "from "+tablename;
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			throw re;
		}
	}
	
	/**
	 * 
	 * Function name:findAll
	 * Description: 查找指定表的所有数据
	 * @param tablename：所要查找的表的名字，表名在tbEntityDAO中有定义
	 * @return：表中所有数据的集合
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	@Override
	public List<T> findAll() {
/*		try {
			String queryString = "from "+tablename;
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			throw re;
		}*/

		Session session = this.getSession();
		try {
			List<T> rs = session.createCriteria(Class.forName(className)).list();
			return rs;
		} catch (Exception e) {
			e.printStackTrace();
			return new ArrayList<T>();
		}finally{
			this.releaseSession(session);
		}
	}

	@Override
	public void update(T obj) {
		super.getHibernateTemplate().update(obj);
	}
	
	/**
	 * 查询非映射实体
	 * @param fullSql
	 * @param clzz
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("hiding")
	public <T> List<T> findObjectsByFullSql(final String fullSql, final Class<T> clzz) throws Exception {
		return findObjectsByFullSql(fullSql, clzz, null);
	}
	
	/**
	 * 查询非映射实体(查询的字段一定要在POJO类中存在)
	 * @param fullSql
	 * @param clzz
	 * @param fieldMappingType 标量查询字段
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({"hiding", "unchecked"})
	public <T> List<T> findObjectsByFullSql(final String fullSql, final Class<T> clzz, final Map<String, NullableType> fieldMappingType) throws Exception {
		return getHibernateTemplate().execute(
				new HibernateCallback<List<T>>() {
					@Override
					public List<T> doInHibernate(Session session)throws HibernateException, SQLException {
						SQLQuery sqlQuery = session.createSQLQuery(fullSql);
						if(fieldMappingType != null){
							for (String field : fieldMappingType.keySet()) {
								if(fieldMappingType.get(field) != null){
									sqlQuery.addScalar(field, fieldMappingType.get(field));
								} else {
									sqlQuery.addScalar(field);
								}
							}
						}
						sqlQuery.setResultTransformer(Transformers.aliasToBean(clzz));
						List<T> list = sqlQuery.list();
						if (CollectionUtils.isEmpty(list)) {
							return new ArrayList<T>();
						}
						return list;
					}
				});
	}

}
